<?

/**
* Gera imagem de captcha utilizando o webservice do site captchas.net
*/
class Qi_Captcha
{
	public $conf = array (
		"client" => "demo",
		"secret" => "secret",
		"random" => null,
		"alphabet" => "abcdefghkmnpqrstuvwxyz2345689", // menos i, l, o, j, 1, 7 e 0 (apenas minusculo)
		"letters" => 4,
		"width" => 128,
		"height" => 75,
		"input_name" => "captcha",
		"case_sensitive" => false
	);

	public function __construct($conf = array())
	{
		$this->conf = array_merge($this->conf, $conf);
	}

	public function verificar($valor_digitado = null)
	{
		$input_name = $this->conf["input_name"];
		if ($valor_digitado === null && isset($_POST[$input_name]))
			$valor_digitado = $_POST[$input_name];
		@session_start();
		if (!isset($_SESSION[$input_name])) return false;
		$fcmp = $this->conf["case_sensitive"] ? "strcmp" : "strcasecmp";
		return $fcmp($valor_digitado, $_SESSION[$input_name]) === 0;
	}
	
	public function img_input()
	{
		$img = $this->img();
		$input = $this->input();
		return <<<EOF
<div class="captcha">
	$img
	$input
</div>
EOF;
	}

	public function input()
	{
		return <<<EOF
<input name="{$this->conf['input_name']}" maxlength="{$this->conf['letters']}" />
EOF;
	}

	public function img()
	{
		$url = $this->url();
		return <<<EOF
<img src="$url" width="{$this->conf['width']}" height="{$this->conf['height']}" />
EOF;
	}
	
	public function url()
	{
		$conf = $this->conf;
		unset($conf["secret"], $conf["input_name"], $conf["case_sensitive"]);
		$query = http_build_query($conf);
		return "http://image.captchas.net?$query";
	}
	
	/**
	 1) Concatenate the secret key and the random string (Example: secretRandomZufall).
	 2) If Alphabet or Letters differs from abcdefghijklmnopqrstuvwxyz/6, append both separated by ':' (<secret><random>:<alphabet>:<letters>).
	 3) Take the MD5-sum of the resulting string (Example: 0x4a 0x7d 0x5d 0xf1 0xdd 0xd7 0x88 0xd4 0x7b 0xd5 0x1e 0x66 0x65 0x45 0xe1 0xec).
	 4) Take the first 6 bytes of the resulting 16-byte-long MD5 value (Example: 74 125 93 241 221 215).
	 5) Determine the remainders of this 6 bytes, when dividing by 26 (Example: 22 21 15 7 13 7).
	 6) Every number encodes a character from the chosen alphabet (Example: "wvphnh").
	*/
	public function gerar_chave()
	{
		if ($this->conf["random"] === null)
			$this->conf["random"] = mt_rand();

		// 1) Concatenate the secret key and the random string (Example: secretRandomZufall).
		extract($this->conf);
		$key = $secret.$random;

		// 2)  If Alphabet or Letters differs from abcdefghijklmnopqrstuvwxyz/6, append both separated by ':' (<secret><random>:<alphabet>:<letters>).
		$key .= ":$alphabet:$letters";

		// 3) Take the MD5-sum of the resulting string
		$md5 = md5($key);
		$md5 = chunk_split($md5, 2, " ");
		$md5 = explode(" ", $md5, $letters + 1);

		// 4) Take the first 6 bytes of the resulting 16-byte-long MD5 value (Example: 74 125 93 241 221 215).
		$firstLetters = array_slice($md5, 0, $letters);

		// 5) Determine the remainders of this 6 bytes, when dividing by 26 (Example: 22 21 15 7 13 7).
		$chave = "";
		$quantidade_letras = strlen($alphabet);
		foreach($firstLetters as $letra):
			$byte = hexdec($letra);
			$resto = $byte % $quantidade_letras;
			$chave .= $alphabet[$resto];
		endforeach;

		@session_start();
		$_SESSION[$this->conf["input_name"]] = $chave;
		return $chave;
	}
}

?>